<?php
namespace Core\Libs\Registry;

class RegistryPath extends \Core\Libs\JabezSingleton\JabezSingleton {

}

class RegistryNamespace extends RegistryPath {

	private static $arrayNamespacesRegistry = array();
	private static $arrayJabezIncRegistry = array();
	private static $arrayDependencesOfPath = array();

	final public static function setNamespacesRegistry($array) {

		self::$arrayNamespacesRegistry =& $array;
	}

	final public static function getNamespacesRegistry() {

		return self::$arrayNamespacesRegistry;
	}

	final public static function setJabezIncRegistry($array) {

		self::$arrayJabezIncRegistry =& $array;
	}

	final public static function getJabezIncRegistry() {

		return self::$arrayJabezIncRegistry;
	}

	private function &getFullStringJabezIncToWebroot($string, $requestType = 'www', $fileTypeExtension = 'css') {

		if($string{0} === '.') {

			return substr(&$string, 1);
		}

		$namespace = \Core\Libs\MasterObject\MasterObject::getConfigRequest('root');
		$string = $namespace.'.'.$requestType.'.'.$fileTypeExtension.'.'.$string;
		return $string;
	}

	final public function &getFilePath($string, $addString = NULL, $idFileType = 'default', $fileTypeExtension = 'view', $checkNamespace = FALSE, $checkErrors = FALSE, $requestType = 'app') {

		return self::_processStringJabezInc(&$string, &$requestType, &$idFileType, &$fileTypeExtension, &$checkErrors, 'pathValidOrNot', &$addString, &$checkNamespace);
	}

	final public static function &getPathOfWebroot($string, $idFileType = 'default', $fileTypeExtension = 'css', $checkErrors = FALSE) {

		$string =& self::getFullStringJabezIncToWebroot($string, 'www', $fileTypeExtension);

		if($idFileType !== 'default') {

			$string = '(' . '@' . $fileTypeExtension . '.' . $idFileType . ')' . $string;
		}

		return self::getFilePath(&$string, NULL, &$idFileType, &$fileTypeExtension, FALSE, &$checkErrors, 'www');
	}

	final public static function &getPathOfImage($string, $type = 'jpg', $checkErros = FALSE) {

		return self::getPathOfWebroot($string, $type, 'img', &$checkErros);
	}

	final public static function &getPathOfJavascript($string, $checkErros = FALSE) {

		return self::getPathOfWebroot(&$string, 'default', 'js', &$checkErros);
	}

	final public static function &getPathOfCss($string, $checkErros = FALSE) {

		return self::getPathOfWebroot(&$string, 'default', 'css', &$checkErros);
	}

	final public static function &getPathOfLayout($string, $addString = NULL, $idFileType = 'default', $fileTypeExtension = 'default', $checkNamespace = FALSE, $checkErrors = FALSE, $requestType = 'app.design.layout') {

		return self::_processStringJabezInc(&$string, &$requestType, &$idFileType, &$fileTypeExtension, &$checkErrors, 'path', &$addString, &$checkNamespace);
	}

	final public static function &getPathOfViewDesign($string, $idFileType = 'default', $fileTypeExtension = 'view', $checkNamespace = FALSE, $checkErrors = FALSE, $requestType = 'app.design.view') {

		return self::_processStringJabezInc(&$string, &$requestType, &$idFileType, &$fileTypeExtension, &$checkErrors, 'path', NULL, &$checkNamespace);
	}

	final public static function &getPathOfNamespace($nameSpace, $idFileType = 'default', $fileTypeExtension = 'default', $checkErrors = FALSE) {

		if(self::namespaceExists(&$nameSpace)) {

			if(is_object(&$nameSpace)) {

				return self::$arrayNamespacesRegistry[get_class(&$nameSpace)]['local'];
			}

			return self::$arrayNamespacesRegistry[$nameSpace]['local'];
		}

		else {

			return self::_processStringJabezInc(&$nameSpace, 'object', &$idFileType, &$fileTypeExtension, &$checkErrors, 'path');
		}
	}

	final public static function &getDependencesOfNamespace($nameSpace, $path = NULL, $idxToken = 0, $continue = TRUE) {

		if(count(&self::$arrayDependencesOfPath[$path]) > 0 && !empty($path)) {

			return self::$arrayDependencesOfPath[$path];
		}

		elseif(count(self::$arrayNamespacesRegistry[$nameSpace]['dependencias']) > 0 && !empty($nameSpace)) {

			return self::$arrayNamespacesRegistry[$nameSpace]['dependencias'];
		}

		else {

			if(empty($path)) {

				return FALSE;
			}

			$ReflexaoClasse =& \Core\Libs\JabezSingleton\JabezSingleton::loadInstance('Core\Libs\Reflection\ReflectionClass', TRUE, TRUE, TRUE, TRUE);
			$arrayDependencias =& $ReflexaoClasse->findNamespacesExternalInFile(&$path, &$nameSpace, &$idxToken, &$continue);

			if(is_array(&$arrayDependencias) && count(&$arrayDependencias) > 0) {

				self::$arrayDependencesOfPath[$path] =& array_merge_recursive((array)self::$arrayDependencesOfPath[$path], &$arrayDependencias);
			}

			unset($ReflexaoClasse, $path, $nameSpace, $idxToken, $continue);
			return $arrayDependencias;
		}

		return FALSE;
	}

	final public static function &addNamespace($array) {

		if(count($array) > 1) {

			foreach($array as $nameSpace => $subArray) {

				if(!self::namespaceExists(&$nameSpace)) {

					self::$arrayNamespacesRegistry[$nameSpace] =& array_merge_recursive((array)self::$arrayNamespacesRegistry[$nameSpace], $subArray);
				}
			}

			unset($array, $subArray, $nameSpace);
		}

		else {

			if(!self::namespaceExists(key(&$array))) {

				self::$arrayNamespacesRegistry =& array_merge_recursive(&self::$arrayNamespacesRegistry, &$array);
				unset($array);
			}
		}
	}

	final public static function &getRegistroJabezInc($stringJabezInc) {

		if(self::registryJabezIncExists($stringJabezInc)) {

			return self::$arrayJabezIncRegistry[$stringJabezInc];
		}

		return FALSE;
	}

	final public static function &addRegistryJabezInc($array) {

		self::$arrayJabezIncRegistry =& array_merge(&self::$arrayJabezIncRegistry, &$array);
	}

	final public static function &deleteRegistryJabezInc($stringJabezInc, $reiniciar = FALSE) {

		if($reiniciar) {

			self::$arrayJabezIncRegistry = array();
		}

		else {

			unset(self::$arrayJabezIncRegistry[$stringJabezInc]);
			self::$arrayJabezIncRegistry =& self::$arrayJabezIncRegistry;
		}
	}

	final public static function &registryJabezIncExists($stringJabezInc) {

		return array_key_exists($stringJabezInc, &self::$arrayJabezIncRegistry);
	}

	final public static function &deleteNamespace($nameSpace, $reiniciar = FALSE) {

		if($reiniciar) {

			self::$arrayNamespacesRegistry = array();
		}

		else {

			unset(self::$arrayNamespacesRegistry[$nameSpace]);
			self::$arrayNamespacesRegistry =& self::$arrayNamespacesRegistry;
		}
	}

	final public static function &deleteDependencesOfNamespace($nameSpace) {

		unset(self::$arrayNamespacesRegistry[$nameSpace]['dependencias']);
		self::$arrayNamespacesRegistry =& self::$arrayNamespacesRegistry;
	}

	final public static function &namespaceExists($nameSpace) {

		if(is_object(&$nameSpace)) {

			return array_key_exists(get_class(&$nameSpace), &self::$arrayNamespacesRegistry);
		}

		elseif($nameSpace{0} === '\\') {

			$nameSpace =& substr(&$nameSpace, 1);
		}

		return array_key_exists($nameSpace, &self::$arrayNamespacesRegistry);
	}

	final public static function &includeFilesRecursively($caminho, $nameSpace = NULL, $continuar = FALSE) {

		$arrayArquivosParaCarregar[0] =& self::getDependencesOfNamespace($nameSpace, $caminho, 0, $continuar);

		if(!is_array($arrayArquivosParaCarregar[0])) {

			self::addNamespace(array($nameSpace => array('local' => $caminho)));
			\Core\Uses\IncluirArquivo(&$caminho);
			return FALSE;
		}

		$arrayTempNameSpacesChecados = array();
		$arrayNameSpacesChecados = array();
		$arrayDependencias = array();
		$chave = key($arrayArquivosParaCarregar[0]);
		$tipoDaChave = $arrayArquivosParaCarregar[0][$chave];
		$chaveInicial = $chave;
		$tipoDaChaveInicial = $tipoDaChave;
		$arrayCaminhosDosArquivosUtilizados['nameSpaces']['internos'] = array();
		$arrayCaminhosDosArquivosUtilizados['nameSpaces']['externos'] = array();
		$carregar = TRUE;
		$idx[0] = 1;

		if(is_array($arrayArquivosParaCarregar[0]) && (!empty($nameSpace) || $nameSpace != NULL)) {

			$arrayDependencias[$nameSpace]['dependencias'] = $arrayArquivosParaCarregar[0];
		}

		while(TRUE) {

			if($carregar) {

				$local = self::getPathOfNamespace($chave, NULL, 'default', TRUE);
				$arrayArquivosParaCarregar[$idx[0]] = self::getDependencesOfNamespace(NULL, $local, 0, TRUE);

				if(is_array($arrayArquivosParaCarregar[$idx[0]])) {

					$arrayDependencias[$chave]['dependencias'] = $arrayArquivosParaCarregar[$idx[0]];

					foreach($arrayArquivosParaCarregar[$idx[0]] as $idx[1] => $idx[2]) {

						$extLocal = self::getPathOfNamespace($idx[1], NULL, 'default', TRUE);

						if($local === $extLocal) {

							$arrayCaminhosDosArquivosUtilizados['nameSpaces']['internos'][$idx[1]] = array('local' => $local);
						}

						else {

							$arrayCaminhosDosArquivosUtilizados['nameSpaces']['externos'][$idx[1]] = array('local' => $extLocal);
							$arrayCaminhosDosArquivosUtilizados['nameSpaces']['externos'][$chave] = array('local' => $local);
						}
					}

					reset($arrayArquivosParaCarregar[$idx[0]]);
				}

				else {

					$arrayCaminhosDosArquivosUtilizados['nameSpaces']['externos'][$chave] = array('local' => $local);
				}
			}

			if(is_array($arrayArquivosParaCarregar[$idx[0]])) {

				$chave = key($arrayArquivosParaCarregar[$idx[0]]);
				$tipoDaChave = $arrayArquivosParaCarregar[$idx[0]][$chave];
				$flagNameSpaceInterno = array_key_exists($chave, &$arrayCaminhosDosArquivosUtilizados['nameSpaces']['internos']);

				if(!$flagNameSpaceInterno && !array_key_exists($chave, &$arrayNameSpacesChecados)) {

					$arrayNameSpacesChecados[$chave] = $tipoDaChave;
					$carregar = TRUE;
				}

				else {

					if(count($arrayArquivosParaCarregar[$idx[0]]) > 1) {

						unset($arrayArquivosParaCarregar[$idx[0]][$chave]);
					}

					else {

						unset($arrayArquivosParaCarregar[$idx[0]]);
						$flagNaoRetornarIdx = TRUE;
					}

					$carregar = FALSE;
					continue;
				}
			}

			elseif(!$arrayArquivosParaCarregar[$idx[0]]) {

				if($idx[0] < 1) {

					$idx[0] = 1;
				}

				if(count($arrayArquivosParaCarregar[$idx[0] - 1]) > 1) {

					if(!$flagNaoRetornarIdx) {

						unset($arrayArquivosParaCarregar[$idx[0]], $arrayArquivosParaCarregar[$idx[0] - 1][$chave]);
						
					}

					else {

						unset($arrayArquivosParaCarregar[$idx[0]]);
					}

					$idx[0] -= 1;
					$flagNaoRetornarIdx = FALSE;
				}

				else {

					if(!$flagNaoRetornarIdx) {

						unset($arrayArquivosParaCarregar[$idx[0]], $arrayArquivosParaCarregar[$idx[0] - 1], $arrayArquivosParaCarregar[$idx[0] - 2][$chave]);
					}
					
					else {

						unset($arrayArquivosParaCarregar[$idx[0]], $arrayArquivosParaCarregar[$idx[0] - 2][$chave]);
					}

					$idx[0] -= 2;
					$flagNaoRetornarIdx = FALSE;
				}

				if($idx[0] < 0) {

					$idx[0] = 0;
				}

				if(!array_key_exists($chave, &$arrayNameSpacesChecados) && !array_key_exists($chave, &$arrayCaminhosDosArquivosUtilizados['nameSpaces']['internos']) && $arrayArquivosParaCarregar[$idx[0]] !== NULL) {

					$chave = key($arrayArquivosParaCarregar[$idx[0]]);
					$tipoDaChave = $arrayArquivosParaCarregar[$idx[0]][$chave];
					$arrayNameSpacesChecados[$chave] = $tipoDaChave;
					$carregar = TRUE;
				}

				elseif(is_array(&$arrayArquivosParaCarregar[0])) {

					$chave = key($arrayArquivosParaCarregar[$idx[0]]);
					$tipoDaChave = $arrayArquivosParaCarregar[$idx[0]][$chave];

					if(!array_key_exists($chave, &$arrayCaminhosDosArquivosUtilizados['nameSpaces']['internos'])) {

						if(!count($arrayArquivosParaCarregar[0]) && !$carregar) {

							$arrayNameSpacesChecados =& array_reverse($arrayNameSpacesChecados);
							break;
						}

						if(!array_key_exists($chave, &$arrayNameSpacesChecados)) {

							$arrayNameSpacesChecados[$chave] = $tipoDaChave;
							$carregar = TRUE;
						}
					}

					else {

						$carregar = FALSE;
						continue;
					}

					if($idx[0] === 0) {

						$auxChave = $chave;
						$auxTipoDaChave = $tipoDaChave;
						unset($arrayArquivosParaCarregar[0][$chave]);
						$chave = key($arrayArquivosParaCarregar[0]);
						$tipoDaChave = $arrayArquivosParaCarregar[0][$chave];
						$carregar = TRUE;

						if(!empty($chave) || $chave != NULL) {

							$arrayNameSpacesChecados[$chave] = $tipoDaChave;
						}

						else {

							$chave = $auxChave;
							$tipoDaChave = $auxTipoDaChave;
							$arrayNameSpacesChecados[$chave] = $tipoDaChave;
						}
					}
				}

				else {

					$carregar = FALSE;
				}
			}

			if(!count($arrayArquivosParaCarregar[0]) && !$carregar) {

				$arrayNameSpacesChecados =& array_reverse($arrayNameSpacesChecados);
				break;
			}

			$idx[0]++;
		}

		unset($arrayNameSpacesChecados[$chaveInicial]);
		$arrayNameSpacesChecados = $arrayNameSpacesChecados + array($chaveInicial => $tipoDaChaveInicial) + array($nameSpace => 'class');
		$arrayTempDiretorios =& array_merge_recursive(&$arrayCaminhosDosArquivosUtilizados['nameSpaces']['internos'], &$arrayCaminhosDosArquivosUtilizados['nameSpaces']['externos'], array($nameSpace => array('local' => &$caminho, 'tipo' => 'class')), &$arrayDependencias);
 		self::addNamespace(&$arrayTempDiretorios);
		$cArrayNameSpacesChecados =& count(&$arrayNameSpacesChecados);
		$idx = 0;

		foreach($arrayNameSpacesChecados as $carregarNameSpace => $tipoDoNameSpace) {

			if(!class_exists($carregarNameSpace) || !interface_exists($carregarNameSpace)) {

				if($idx < ($cArrayNameSpacesChecados - 1) && !array_key_exists(&$carregarNameSpace, &$arrayTempDiretorios)) {

					$auxCaminho =& self::getPathOfNamespace($carregarNameSpace, $tipoDoNameSpace);
				}

				else {

					$auxCaminho = $arrayTempDiretorios[$carregarNameSpace]['local'];
				}

				if($idx === ($cArrayNameSpacesChecados - 1) || $caminho !== $auxCaminho) {

					if(!empty($auxCaminho)) {

						\Core\Uses\IncluirArquivo(&$auxCaminho);
					}				
				}
			}

			$idx++;
		}

		unset($arrayTempNameSpacesChecados, $arrayNameSpacesChecados, $arrayTempDiretorios, $arrayArquivosParaCarregar);
	}
	
	/**
	 * NameSpace Class: \Core\Libs\Registro\RegistroNameSpace
	 * Método: _getIdTipoDoNameSpace
	 * Acesso: Privado.
	 * Uso: Privado do Framework.
	 * 
	 * Método recebe uma string do formato StringJabezInc, Exemplos:
	 *
	 * 	Core.Libs.Objeto::Objeto
	 * 	Core:Web.Libs.Teste
	 * 	Core.Modules.Web.Libs.Teste
	 * 	Plugins(Teste).Libs.Math::add
	 *  Plugins(Teste).Modules(Web).Libs.Math::add
	 * 
	 * Verifica se possui uma chamada a um Módulo, se possuir retorna um Array ou somente o Tipo,
	 * isso depende do parametro returnType. 0: Type, 1: Array, 2: Array Object Interator.
	 * 
	 * Parametros:
	 * @$string = string.
	 * @$returnType = integer.
	 * 
	 * Retorno:
	 * Type, Array ou ArrayObject.
	 */

	final private static function getNamespaceType($string, $returnType = 1) {

		if(!is_array(&$string)) {

			$arrayString =& explode('.', &$string);
		}

		$string =& mb_strtolower(&$arrayString[0]);

		if($string === 'core' || $string == 'jabez-php' || $string === 'jabezphp') {

			$idTypeNameSpace = 0;
		}

		elseif(preg_match('/^plugin(s)?/i', &$string)) {

			$idTypeNameSpace = 4;
		}

		elseif(preg_match('/^package(s)?/i', &$string)) {

			$idTypeNameSpace = 5;
		}

		else {

			$idTypeNameSpace = 1;
		}

		if($returnType === 1) {

			return array('idTypeNameSpace' => &$idTypeNameSpace, 'arrayString' => &$arrayString);
		}

		elseif($returnType === 0) {

			return $idTypeNameSpace;
		}

		return FALSE;
	}

	/**
	 * NameSpace Class: \Core\Libs\Registro\RegistroNameSpace
	 * Método: _getIdTipoDoNameSpace
	 * Acesso: Público.
	 * Uso: Público.	 * 
	 * 
	 * Método recebe uma string do formato StringJabezInc, Exemplos:
	 *
	 * 	Core.Libs.Objeto::Objeto
	 * 	Core:Web.Libs.Teste
	 * 	Core.Modules.Web.Libs.Teste
	 * 	Plugins(Teste).Libs.Math::add
	 *  Plugins(Teste).Modules(Web).Libs.Math::add
	 * 
	 * Faz uma série de formatações, para montar uma string que será utilizada para por Exemplo:
	 * 
	 * 	1. Criar ou retornar uma instância de classe.
	 * 	2. Chamar uma função.
	 *  3. Outras utilizadades do namespace.
	 * 
	 * Faz uma busca nos diretórios padrões ou pode receber um parametro extra
	 * indicando o ID alias do diretório extra cadastrado juntamente
	 * com os tipos de arquivos que o diretório pode conter. Exemplo:
	 * 
	 * 	Core.Libs(dirExtraLibs).Objeto::Objeto
	 * 
	 * No cadastro o ID alias, dirExtraLibs conterá o caminho para um diretório (conforme cadastrado): \jabez-php\jabez\app\libs2\Objeto
	 * 
	 * Parametros:
	 * @$string = string.
	 *
	 * Retorno:
	 * string , Array ou ArrayObject.
	 */

	final public static function &_processStringJabezInc($string, $requestType = 'app', $idFileType = NULL, $fileTypeExtension = 'default', $checkErrors = TRUE, $return = 'array', $addString = NULL, $checkNamespace = TRUE) {

		$match = array();
		$arrayString = array();
		$idTypeNameSpace = 0;
		$cExtensionTypeShortcut = 0;
		$flagIndexed = FALSE;
		$flagStringTypeNameSpace = FALSE;
		$flagSkipAddArrayString = FALSE;
		$flagOverwriteRegisteredExtensions = FALSE;
		$flagSkipRootDirectory = FALSE;
		$flagModule = FALSE;
		$idAppModule = '';
		$idAppPlugin = '';
		$idDirectory = 'default';
		$extensionFile = '';
		$idFileType = '';
		$idxDirectory = NULL;
		$nameSpace = '';

		if($string{0} === '\\') {

			$string =& mb_substr(&$string, 1);
		}

		if(!preg_match('/(?<!\\\)\./', &$string)) {

			$flagStringTypeNameSpace = TRUE;
			$string =& str_replace('\\', '.', &$string);

			if($fileTypeExtension === 'extends') {

				$fileTypeExtension = 'class';
			}

			elseif($fileTypeExtension === 'implements') {

				$fileTypeExtension = 'interface';
			}
		}

		$stringJabezInc =& mb_strtolower(&$string);
		$flagArray =& self::getRegistroJabezInc($stringJabezInc);

		if($flagArray && $return === 'array') {

			return $flagArray + array('flag' => TRUE);
		}

		elseif(!empty($flagArray['caminho']) && $return === 'path') {

			return $flagArray['caminho'];
		}

		unset($flagArray);
		$flagOverwriteExtensions =& preg_match('/^(\(|\[).+(\)|\])(?![^a-zA-Z0-9\_\-])/', &$string, &$match[0]);

		if($flagOverwriteExtensions) {

			$string =& preg_split('/^(\(|\[).+(\)|\])(?![^a-zA-Z0-9\_\-])/', preg_replace('/\.{2}+/', '.', &$string), -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
			preg_match('/(?<=(\(|\[))(.+)(?<!\)|\])/', &$match[0][0], &$match[1]);

			if($match[1][0]{0} === '@') {

				$idFileType =& mb_substr(&$match[1][0], 1);

				if(strpos($idFileType, '.')) {

					list($idFileType, $fileTypeExtension, $fileContentTypeExtension) = explode('.', $idFileType);

					if(empty($fileTypeExtension)) {

						$fileTypeExtension = 'default';
					}

					if(empty($fileContentTypeExtension)) {

						$fileContentTypeExtension = 'default';
					}
				}

				else {

					$fileTypeExtension = 'default';
					$fileContentTypeExtension = 'default';
				}

				$flagOverwriteExtensions = FALSE;
				$flagOverwriteRegisteredExtensions = TRUE;
			}

			else {

				$match[1][0] = preg_replace('/\.{2}+/', '\\.', $match[1][0]);
				$arrayOverwriteExtensions =& preg_split('/(?<!\\\)\./', $match[1][0]);
				$fileTypeExtension = '.' . str_replace('\\', '', $arrayOverwriteExtensions[0]);

				(!empty($arrayOverwriteExtensions[1])) ? $fileType = '.' . str_replace('\\', '', $arrayOverwriteExtensions[1]) : $fileType = '';
				(!empty($arrayOverwriteExtensions[2])) ? $extensionFile = '.' . str_replace('\\', '', $arrayOverwriteExtensions[2]) :  $extensionFile = '';
			}

			$string =& $string[2];
		}

		if(empty($idFileType)) {

			$idFileType = 'default';
		}

		extract(self::getNamespaceType($string, 1), EXTR_REFS & EXTR_OVERWRITE);
		$totalParams = $cArrayString = count(&$arrayString);

		if($cArrayString === 1) {

			if($return === 'array') {

				return array('idClasse' => $string, 'classe' => $string, 'nameSpace' => $string, 'caminho' => FALSE, 'totalParams' => &$totalParams);
			}

			return FALSE;
		}

		if(!$flagStringTypeNameSpace) {

			(strpos(&$arrayString[$cArrayString - 1], '::') !== FALSE) ? list($fileName, $call) = explode('::', &$arrayString[$cArrayString - 1]) : $fileName = $call = $arrayString[$cArrayString - 1];
			unset($arrayString[$cArrayString - 1]);
			unset($string);
		}

		else {

			$fileName = $arrayString[$cArrayString - 2];
			$call = $arrayString[$cArrayString - 1];
			unset($arrayString[$cArrayString - 1], $arrayString[$cArrayString - 2]);
		}

		if(empty($call)) {

			$call = $fileName;
		}

		$addArrayString = array();

		if($idTypeNameSpace === 4) {

			if($flagStringTypeNameSpace === TRUE) {

				if(empty($arrayString[1])) {

					throw \Core\Uses\Exception('Erro: Nome do Plugin não informado.');
				}

				$idAppPlugin = $arrayString[1];

				if(preg_match('/module(s)?/i', $arrayString[3])) {

					$flagModule = TRUE;
					$idAppModule = $arrayString[4];

					if(preg_match('/module(s)?/i', $arrayString[6])) {

						throw \Core\Uses\Exception('Erro: Módulo não pode conter outros modulos.');
					}

					elseif(empty($idAppModule)) {

						throw \Core\Uses\Exception('Erro: Nome do Módulo não informado.');
					}

					elseif(preg_match('/extension(s)?/i', $arrayString[5])) {

						$requestType = 'app.extensions.*';
					}

					$addArrayString = array('Plugins', $idAppPlugin, 'Extensions', 'Modules', $idAppModule);
				}

				elseif(preg_match('/extension(s)?/i', $arrayString[2])) {

					$addArrayString = array('Plugins', $idAppPlugin);
					$requestType = 'app.extensions.*';
				}

				else {

					$addArrayString = array('Plugins', $idAppPlugin);
				}
			}

			else {

				if(strpos($arrayString[0], ':') !== FALSE) {

					preg_match('/plugin(?:s)?.([a-z0-9\_\-]+)\:([a-z0-9\_\-]+)./i', $arrayString[0] . '.', $match);
					array_splice($arrayString, 0, 1, array('Plugins', $match[1], 'Extensions', 'Modules', $match[2]));
					$flagModule = TRUE;
					$idAppModule = $match[2];
					$idAppPlugin = $match[1];
					//$cExtensionTypeShortcut = 4;
				}

				else {

					if(strpos($arrayString[1], ':') !== FALSE) {

						list($idAppPlugin, $idAppModule) = explode(':', $arrayString[1]);
						array_splice($arrayString, 1, 1, array($idAppPlugin, 'Extensions', 'Modules', $idAppModule));
						$flagModule = TRUE;
						//$cExtensionTypeShortcut = 4;
					}

					elseif(preg_match('/\(|\[/i', $arrayString[0])) {

						preg_match('/plugin(?:s)?.([a-z0-9\_\-]+)./i', $arrayString[0] . '.', $match);
						array_splice($arrayString, 0, 1, array('Plugins', $match[1]));
						$idAppPlugin = $match[1];
						//$cExtensionTypeShortcut = 4;
					}

					else {

						$idAppPlugin = $arrayString[1];
						//$cExtensionTypeShortcut = 1;

						if(preg_match('/module(s)?/i', $arrayString[3])) {

							$flagModule = TRUE;
							$idAppModule = $arrayString[4];
							//$cExtensionTypeShortcut = 4;
						}
					}
				}

				$cExtensionTypeShortcut = 1;

				if(empty($idAppPlugin)) {

					throw \Core\Uses\Exception('Erro: Nome do Plugin não informado.');
				}

				if($flagModule) {

					if(preg_match('/module(s)?/i', $arrayString[6])) {

						throw \Core\Uses\Exception('Erro: Módulo não pode conter outros modulos.');
					}

					elseif(empty($idAppModule)) {

						throw \Core\Uses\Exception('Erro: Nome do Módulo não informado.');
					}

					if(preg_match('/extension(s)?/i', $arrayString[5])) {

						$requestType = 'app.extensions.*';
					}

					$addArrayString = array('Plugins', $idAppPlugin, 'Extensions', 'Modules', $idAppModule);
					$cAddArrayString = 0;
					$cExtensionTypeShortcut = 4;
				}

				else {

					if(preg_match('/extension(s)?/i', $arrayString[2])) {

						$requestType = 'app.extensions.*';
					}

					$addArrayString = array('Plugins', $idAppPlugin);
					$cAddArrayString = 0;
				}
			}
		}

		elseif($idTypeNameSpace === 5) {

			//$idAppType = 'packages';
			//$nameSpace = $idAppType.'\\';
			//$idFileType = 'libs';
			//$addIdx = 1;
		}

		else {

			if($flagStringTypeNameSpace === TRUE) {

				$idAppName = $arrayString[0];

				if(preg_match('/module(s)?/i', $arrayString[2])) {

					$flagModule = TRUE;
					$idAppModule = $arrayString[3];

					if(preg_match('/extension(s)?/i', $arrayString[4])) {

						if(preg_match('/module(s)?/i', $arrayString[5])) {

							throw \Core\Uses\Exception('Erro: Módulo não pode conter outros modulos.');
						}

						elseif(empty($idAppModule)) {

							throw \Core\Uses\Exception('Erro: Nome do Módulo não informado.');
						}

						$addArrayString = array($idAppName, 'Extensions', 'Modules', $idAppModule);
						$requestType = 'app.extensions.*';
					}

					else {

						$addArrayString = array($idAppName, 'Extensions', 'Modules', $idAppModule);
					}
				}

				elseif(preg_match('/extension(s)?/i', $arrayString[1])) {

					if(empty($arrayString[2])) {

						throw \Core\Uses\Exception('Erro: Tipo da Extension não informada.');
					}

					elseif(empty($arrayString[3])) {

						throw \Core\Uses\Exception('Erro: Nome da Extension não informada.');
					}

					$addArrayString = array($idAppName);
					$requestType = 'app.extensions.*';
				}

				else {

					$addArrayString = array($idAppName);
				}
			}

			else {

				if(strpos($arrayString[0], ':') !== FALSE) {

					$flagModule = TRUE;
					$flagSkipAddArrayString = TRUE;
					$idCheckSubModule = 2;
					list($idAppName, $idAppModule) = explode(':', $arrayString[0]);
				}

				else {

					$idAppName = $arrayString[0];

					if(preg_match('/module(s)?/i', $arrayString[2])) {

						$flagModule = TRUE;
						$idAppModule = $arrayString[3];
						$idCheckSubModule = 5;

						if($flagStringTypeNameSpace) {

							$flagSkipAddArrayString = TRUE;
						}
					}
				}

				if((empty($idAppName) && empty($arrayString[0])) || (!empty($idAppModule) && empty($idAppName))) {

					throw \Core\Uses\Exception('Erro: Nome da Aplicação não informada.');
				}

				if($flagModule === TRUE) {

					if(preg_match('/module(s)?/i', $arrayString[$idCheckSubModule])) {

						throw \Core\Uses\Exception('Erro: Módulo não pode conter outros modulos.');
					}

					elseif(preg_match('/extension(s)?/i', $arrayString[$idCheckSubModule - 1])) {

						$requestType = 'app.extensions.*';
					}

					if($flagSkipAddArrayString) {

						$addArrayString = array($idAppName, 'Extensions', 'Modules', $idAppModule);
						$cAddArrayString = 0;
					}

					else {

						$addArrayString = array($idAppName);
						$cAddArrayString = 3;
					}
				}

				else {

					if(preg_match('/extension(s)?/i', $arrayString[1])) {

						$requestType = 'app.extensions.*';
					}

					$addArrayString = array($idAppName);
					$cAddArrayString = 0;
				}
			}
		}

		$match = array();
		$cAddArrayString += count($addArrayString);

		if(!$flagStringTypeNameSpace) {

			foreach($arrayString as $idx => &$id) {

				if(preg_match('/[^a-z0-9\_\-]([a-z0-9\_\-]+)[^a-z0-9\_\-]/i', &$id, $match)) {

					$id =& preg_replace('/[^a-z0-9\_\-]([a-z0-9\_\-]+)[^a-z0-9\_\-]/i', '', &$id);

					if($idx > 0) {

						$idDirectory = $match[1];
						$idxDirectory = $idx + $cAddArrayString - (1 + $cExtensionTypeShortcut);
					}
				}
			}

			if($flagSkipAddArrayString) {

				array_splice($arrayString, 0, 1 + $cExtensionTypeShortcut, $addArrayString);
			}
		}

		$match = array();
		$nameSpace = \Core\Libs\Extend\Config::getNamespace(implode('\\', $arrayString).'\\'.$fileName.'\\'.$call);

		if(($requestType === 'www' || $requestType === 'temporary') && !$flagModule) {

			$rootDirectory = '';
			$flagSkipRootDirectory = TRUE;
		}

		else {

			$rootDirectory = \Core\Libs\Extend\Directory::getRootDirectory(implode('.', $addArrayString), TRUE);
		}

		if($requestType === 'app.design.view' || $requestType === 'app.extensions.*') {

			$genericSubDir =& strtolower(preg_replace_callback('/(?<=.)[A-Z]{1,1}/', create_function('$match', 'return \'-\'.$match[0];'), array_pop($arrayString)));

			if($requestType === 'app.design.view') {

				$fileName =& mb_strtolower(&$fileName);
				$nameSpace = preg_replace('/[a-zA-Z0-9\_]+$/', &$fileName, &$nameSpace);
			}
		}

		if($flagStringTypeNameSpace) {

			if(!empty($rootDirectory)) {

				$rootDirectory = '.' . $rootDirectory;
			}

			$stringIniPathDir = preg_replace_callback('/(?<=[a-z])[A-Z]{1,1}/', create_function('$match', 'return \'-\'.$match[0];'), implode('.', $addArrayString)).'.dir'.$rootDirectory;
		}

		else {

			if($idxDirectory !== NULL) {

				array_splice($arrayString, $idxDirectory, 1, array($arrayString[$idxDirectory], $idDirectory));
			}

			else {

				$stringIniPathDir = '.' . $idDirectory;
			}

			if(!empty($rootDirectory) && (!$flagModule || !$flagSkipRootDirectory)) {

				array_splice($arrayString, $cAddArrayString - 1, 1, array($arrayString[$cAddArrayString - 1], 'dir', $rootDirectory));
			}

			else {

				array_splice($arrayString, $cAddArrayString - 1, 1, array($arrayString[$cAddArrayString - 1], 'dir'));
			}

			$stringIniPathDir = preg_replace_callback('/(?<=[a-z])[A-Z]{1,1}/', create_function('$match', 'return \'-\'.$match[0];'), implode('.', $arrayString)) . $stringIniPathDir;
		}

		//\core\uses\dump('String Ini Path Dir: '.$stringIniPathDir);
		$arrayDir = \Core\Uses\Ler($stringIniPathDir, TRUE, 'array');
		$requestStatus = FALSE;
		//\core\uses\dump('Namespace: '.$nameSpace);

		if(!is_array(&$arrayDir)) {

			if($checkErrors === TRUE) {

				throw \Core\Uses\Exception('Caminho não cadastrado para a requisição solicitada.');
			}

			return FALSE;
		}

		elseif(!$flagStringTypeNameSpace && $idxDirectory !== NULL && $checkErrors === TRUE && !$flagOverwriteExtensions && !$flagOverwriteRegisteredExtensions && (!is_array($arrayDir['_value']['contents']) || count($arrayDir['_value']['contents']) < 1)) {

			throw \Core\Uses\Exception('Tipos de arquivos que o alias ID do diretório: [ '.$idDirectory.' ] pode conter não foi cadastrado.');
		}

		$arrayTempContents = array();

		if($flagOverwriteRegisteredExtensions) {

			$arrayTempContents = \Core\Libs\Extend\Directory::getDefaultExtensions('array');
		}

		gotoCheckInterfaceExists:

		if(!$flagStringTypeNameSpace) {

			$path = $arrayDir['_value']['path'];

			if(!empty($path)) {

				if(!$flagOverwriteExtensions) {

					if($flagOverwriteRegisteredExtensions) {

						$arrayTempContents = $arrayTempContents[$idFileType]['contents'][$fileTypeExtension];
					}

					else {

						$arrayTempContents = $arrayDir['_value']['contents'][$fileTypeExtension];
					}

					if(!empty($arrayTempContents)) {

						//$arrayTempContents = $arrayDir['_value']['contents'][$fileTypeExtension];
						$isArrayTempContents = current($arrayTempContents);

						if(is_array($isArrayTempContents)) {

							if(!empty($arrayTempContents[$fileContentTypeExtension])) {

								$arrayTempContents = $arrayTempContents[$fileContentTypeExtension];
							}

							else {

								$arrayTempContents['file'] = '';
								$arrayTempContents['type'] = '';
								$arrayTempContents['ext'] = '.php';
							}
						}

						$auxFileName = $genericSubDir . DS . $fileName . $arrayTempContents['file'] . $arrayTempContents['type'] . $arrayTempContents['ext'];
						unset($arrayTempContents);
					}

					else {

						$auxFileName = $genericSubDir . DS . $fileName . '.php';
					}
				}

				else {

					$auxFileName = $genericSubDir . DS . $fileName . $fileTypeExtension . $fileType . $extensionFile;
				}

				$path .= $auxFileName;
			}

			else {

				$path = FALSE;
			}

			$path = preg_replace('/'.DS.DS.'+/', DS, $path);
			$pathFound = $path;
//echo $path.'<br>';
			if(\Core\Uses\ChecarArquivo(&$path) && (!$checkNamespace || \Core\Libs\Reflection\ReflectionFile::checkNamespacesInFile(&$path, $nameSpace))) {

				$requestStatus = TRUE;
			}

			else {

				$requestStatus = FALSE;
				$path = FALSE;
			}
		}

		else {

			$arrayConfigFound = array();
			$arrayConfig = array();
			$arrayConfigFound =& self::getPossiblePathsOfNamespace($arrayDir);

			foreach($arrayConfigFound as $arrayConfig) {

				if($flagOverwriteRegisteredExtensions) {

					$arrayTempContents = $arrayTempContents[$idFileType]['contents'][$fileTypeExtension];
				}

				else {

					$arrayTempContents = $arrayConfig['contents'][$fileTypeExtension];
				}

				$path = $arrayConfig['path'] . DS;

				if(!$flagOverwriteExtensions) {

					if(!empty($arrayTempContents)) {

						$auxFileName = $genericSubDir . DS . $fileName . $arrayTempContents['file'] . $arrayTempContents['type'] . $arrayTempContents['ext'];
					}

					else {

						$auxFileName = $genericSubDir . DS . $fileName . '.php';
					}
				}

				else {

					$auxFileName = $genericSubDir . DS . $fileName . $fileTypeExtension . $fileType . $extensionFile;
				}

				unset($arrayTempContents);
				$path = preg_replace('/'.DS.DS.'+/', DS, $path.$auxFileName);
				$pathFound = $path;
//echo $path.'<br>';
				if(\Core\Uses\ChecarArquivo(&$path) && (!$checkNamespace || \Core\Libs\Reflection\ReflectionFile::checkNamespacesInFile(&$path, $nameSpace))) {

					$requestStatus = TRUE;
					break;
				}

				else {

					$requestStatus = FALSE;
					$path = FALSE;
				}

				$auxFileName = NULL;
			}

			if($requestStatus === TRUE) {

				self::addNamespace(array($nameSpace => array('local' => $path)));
			}
		}

		if($requestStatus === FALSE && $flagStringTypeNameSpace && !$flagOverwriteExtensions && !isset($gotoCheckInterfaceExists)) {

			$fileTypeExtension = 'interface';
			$gotoCheckInterfaceExists = TRUE;
			goto gotoCheckInterfaceExists;
		}

		$arrayConfigStringsJabezInc = array('idClasse' => &$nameSpace, 'classe' => &$nameSpace, 'nameSpace' => &$nameSpace, 'caminho' => &$path, 'totalParams' => &$totalParams);
		self::addRegistryJabezInc(array($stringJabezInc => &$arrayConfigStringsJabezInc));

		if($return === 'path') {

			return $path;
		}

		elseif($return === 'pathValidOrNot') {

			return $pathFound;
		}

		elseif($return === 'array') {

			return $arrayConfigStringsJabezInc;
		}
	}

	private static function &getPossiblePathsOfNamespace($iterator, $flagGetObject = TRUE, $auxKey = NULL, $arrayReturn = array()) {

		if(!is_object(&$iterator) && $flagGetObject === TRUE) {

			$iterator = new \RecursiveArrayIterator($iterator);
			$flagGetObject = FALSE;
		}

		while($iterator->valid()) {

			if($iterator->key() === '_value') {

				if($auxKey !== 'name') {

					$current = $iterator->current();

					if(!empty($current)) {

						$arrayReturn[] = $iterator->current();
					}
				}

				else {

					$auxKey = NULL;
				}
			}

			elseif($iterator->hasChildren()) {

				self::getPossiblePathsOfNamespace($iterator->getChildren(), $flagGetObject, $iterator->key(), &$arrayReturn);
			}

			else {

				$auxKey =& $iterator->key();
			}

			$iterator->next();
		}

		if(!$iterator->valid()) {

			unset($iterator);

			if(is_array($arrayReturn)) {

				return $arrayReturn;
			}

			return FALSE;
		}
	}
}

class RegistryClass extends RegistryNamespace {

	//public static $new;
	private static $resetProperties = TRUE;
	private static $_classSingleton = NULL;

	final public function &params() {

		self::$_arrayParams =& func_get_args();
		return $this;
	}

	final public function &setClassSingleton($bool = TRUE) {

		self::$_classSingleton =& $bool;
		return $this;
	}

	final public function &setResetProperties($bool = TRUE) {

		self::$resetProperties =& $bool;
		return $this;
	}

	final public function &getClassSingleton() {

		return self::$_classSingleton;
	}

	final public function &getResetProperties() {

		return self::$resetProperties;
	}

	final public static function getClass($path) {

		return self::getInstance(&$path);
	}

	final public static function getObject($path) {

		return self::getInstance(&$path);
	}

	final public static function &getInstance($path) {

		//self::$_newClasseAtivo = TRUE;
		$totalParams = 0;
		$caminho = NULL;
		$auxCaminho = NULL;
		$nameSpace = NULL;
		$idClasse = NULL;
		$carregarNameSpace = NULL;

		extract(self::_processStringJabezInc(&$path, 'object', NULL, 'class', TRUE, 'array'), EXTR_REFS & EXTR_OVERWRITE);

		if($totalParams > 1) {

			try {

				if(empty(self::$_arrayInstancias[$idClasse]) || !is_object(self::$_arrayInstancias[$idClasse])) {

					 parent::includeFilesRecursively($caminho, $nameSpace, TRUE);
				}
			}

			catch(\Exception $e) {

				if(empty($auxCaminho)) {

					$auxCaminho = $caminho;
				}

				if(!strpos(&$carregarNameSpace, T_NS_SEPARATOR)) {

					$carregarNameSpace = 'Namespace em formato inválido.';
				}

				throw \Core\Uses\Exception('Falha ao incluir o arquivo: '.$auxCaminho.'<br>'.'Namespace não incluído e não carregado: '.$carregarNameSpace.'<br>'.'Erro interno do php: '.$e->getMessage());
			}
		}

		$clsSing = self::$_arrayInstances[$idClasse]['properties']['classeSingleton'];
		$totalParams =& count(&self::$_arrayParams);

		if($clsSing === NULL) {

			$clsSing = self::$_classSingleton;

			if($clsSing === NULL) {

				$clsSing = self::$classeSingleton;
			}
		}

		$init =& self::loadInstance(array(&$nameSpace, &$idClasse), &$clsSing, FALSE, 'reflection', TRUE);

		if(method_exists(&$nameSpace, '__construct') || $totalParams) {

			if($totalParams) {

				$arrayParams =& self::$_arrayParams;

				try {

					$arrayParamsReflection =& $init->getMethod('__construct')->getParameters();

					if(!count(&$arrayParamsReflection)) {

						throw \Core\Uses\Exception('Construtor não possui parametros ou não existe.');
					}

					$arrayNewParams = array();

					foreach($arrayParamsReflection as $i => $param) {

						if($param->isPassedByReference()) {

							$arrayNewParams[$i] =& $arrayParams[$i];
						}

						else {

							$arrayNewParams[$i] = $arrayParams[$i];
						}
					}
				}

				catch(\Exception $e) {

					throw \Core\Uses\Exception('Construtor nao possui parametros ou nao existe.');
				}

				$reflection =& self::loadInstance(array(&$nameSpace, &$idClasse), &$clsSing, self::$resetProperties, TRUE, FALSE, array(&$arrayNewParams));
				unset($init, $arrayParamsReflection, $arrayNewParams);
				self::$_classSingleton = self::$_arrayParams = NULL;
				self::$resetProperties = TRUE;
				return $reflection;
			}

			else {

				$reflection =& self::loadInstance(array(&$nameSpace, &$idClasse), &$clsSing, self::$resetProperties, TRUE, FALSE, TRUE);
				unset($init);
				self::$_classSingleton = NULL;
				self::$resetProperties = TRUE;
				return $reflection;
			}
		}

		else {

			$reflection =& self::loadInstance(array(&$nameSpace, &$idClasse), &$clsSing, self::$resetProperties, TRUE, FALSE);
			unset($init);
			self::$_classSingleton = NULL;
			self::$resetProperties = TRUE;
			return $reflection;
		}
	}
}
?>